package gosu;

import java.awt.event.KeyEvent;
import java.awt.event.InputEvent;
import static java.awt.event.KeyEvent.*;


public class TextInput {
  private String _text;
  private int _caretPos;
  private int _selectionStart;

  public TextInput() {
    _text = "";
  }


  public String getText() { return _text; }


  public void setText(String text) {
    _text = text;
    _caretPos = _selectionStart = _text.length();
  }


  public int getCaretPos() { return _caretPos; }


  public int getSelectionStart() { return _selectionStart; }


  protected boolean feedEvent(InputEvent ie) {
    if (!(ie instanceof KeyEvent)) return false;

    KeyEvent event = (KeyEvent) ie;

    char c = event.getKeyChar();

    if (c != CHAR_UNDEFINED && c >= 32 && c != 127) {
      // If text is selected, it will get overwritten
      int min = Math.min(_caretPos, _selectionStart);
      int max = Math.max(_caretPos, _selectionStart);

      _text = _text.substring(0, min) + c + _text.substring(max);

      _caretPos = _selectionStart = min + 1;

      return true;
    }

    switch (event.getKeyCode()) {
      case VK_LEFT:
        moveLeft(event);
        return true;

      case VK_RIGHT:
        moveRight(event);
        return true;

      case VK_HOME:
        _caretPos = 0;
        if (!event.isShiftDown()) _selectionStart = _caretPos;
        return true;

      case VK_END:
        _caretPos = _text.length();
        if (!event.isShiftDown()) _selectionStart = _caretPos;
        return true;

      case VK_BACK_SPACE:
        if (_caretPos != _selectionStart) {
          deleteSelection();
        } else {
          int oldCaret = _caretPos;
          moveLeft(event); // move left either a character or a word
          _text = _text.substring(0, _caretPos) + _text.substring(oldCaret);
          _selectionStart = _caretPos;
        }
        return true;

      case VK_DELETE:
        if (_caretPos != _selectionStart) {
          deleteSelection();
        } else {
          int oldCaret = _caretPos;
          moveRight(event); // move right either a character or a word
          _text = _text.substring(0, oldCaret) + _text.substring(_caretPos);
          _selectionStart = _caretPos = oldCaret;
        }
        return true;

    }
    return false;
  }


  private void moveLeft(KeyEvent event) {
    if (event.isControlDown()) {
      // move left a word

      while (_caretPos > 0 && Character.isWhitespace(_text.charAt(_caretPos - 1))) {
        _caretPos--;
      }

      while (_caretPos > 0 && !Character.isWhitespace(_text.charAt(_caretPos - 1))) {
        _caretPos--;
      }
      
    } else {
      // move left a character
      if (_caretPos > 0) _caretPos--;
    }

    if (!event.isShiftDown()) _selectionStart = _caretPos;
  }


  private void moveRight(KeyEvent event) {
    if (event.isControlDown()) {
      // move right a word

      while (_caretPos < _text.length() && Character.isWhitespace(_text.charAt(_caretPos))) {
        _caretPos++;
      }

      while (_caretPos < _text.length() && !Character.isWhitespace(_text.charAt(_caretPos))) {
        _caretPos++;
      }

    } else {
      // move right a character
      if (_caretPos < _text.length()) _caretPos++;
    }

    if (!event.isShiftDown()) _selectionStart = _caretPos;
  }


  private void deleteSelection() {
    int min = Math.min(_caretPos, _selectionStart);
    int max = Math.max(_caretPos, _selectionStart);

    _text = _text.substring(0, min) + _text.substring(max);

    _caretPos = _selectionStart = min;
  }
}
